#include "myTask.h"
#include "cmdProcess.h"
#include "ws2812.h"
#include <stdio.h>
#include <string.h>
#include "rc522.h"
#include "jdy25m.h"
#include "koroCard.h"

void task_hartbeat_func(void *param);
void task_ws2812_func(void *param);
void task_ws2812d_func(void *param);
void task_rc522_func(void *param);
void task_battery_func(void *param);

uint8_t wsAnimeFlag = 0;
uint8_t wsAnimeTimeFlag = 0;
uint8_t wsAnimeTime = 0;

volatile uint32_t realTicks; // 系统时间，溢出处理 todo

// 电压-电量表
const unsigned short volTable[11] = {
    [0] = 300,
    [1] = 345,
    [2] = 374,
    [3] = 377,
    [4] = 379,
    [5] = 382,
    [6] = 387,
    [7] = 392,
    [8] = 398,
    [9] = 406,
    [10] = 420,
};


// 任务控制块数组
taskCtrl taskList[] = {
    [0] = {
        .run = 1, // 立即执行
        .tickCounts = 10000,
        .tickReload = 10000,
        .flag = NULL,
        .pTaskFunc = task_hartbeat_func,
    },

    [1] = {
        .run = 0,
        .tickCounts = 0, // 挂起
        .tickReload = 1,
        .flag = &wsAnimeFlag,
        .pTaskFunc = task_ws2812_func,
    },

    [2] = {
        .run = 0,
        .tickCounts = 0, // 挂起
        .tickReload = 1,
        .flag = &wsAnimeTimeFlag,
        .pTaskFunc = task_ws2812d_func,
    },

    [3] = {
        .run = 0,
        .tickCounts = 500, // 挂起
        .tickReload = 500,
        .flag = NULL,
        .pTaskFunc = task_rc522_func,
    },

    [4] = {
        .run = 0,
        .tickCounts = 1000,
        .tickReload = 1000,
        .flag = NULL,
        .pTaskFunc = task_battery_func,
    },

    // end
    {
        .tickReload = 0,
    },
};

// 心拍任务：10s 发送一次心跳 log
void task_hartbeat_func(void *param){
    static uint32_t count = 1;

    // printf_DMA(PRINT_DEBUG"Heart beat: %d\n", count ++);
}

// ws2812 绘制特定动画任务：由标志位驱动，非定期任务
void task_ws2812_func(void *param){
    static uint32_t delayOverTick = 0;
    uint8_t *flag = ((taskCtrl *)param)->flag;
    static uint8_t lastFlagStatus = 0;

    switch(*flag){
        case 0: // 挂起
            ((taskCtrl *)param)->tickCounts = 0;
            lastFlagStatus = 0;
            break;

        case 1: // 停止刷新
            *flag = 0;
            lastFlagStatus = 1;
            break;
            
        case 2: // 清空显示
            *flag = 0;
            lastFlagStatus = 2;
            HAL_Delay(1);
            ws2812_set_all_color(&myWs, 0, 0, 0);
            ws2812_refresh(&myWs);
            break;

        default:
            if(lastFlagStatus <= 2){
                delayOverTick = 1;
                ((taskCtrl *)param)->tickCounts = 1;
            }
            lastFlagStatus = *flag;

            if(((delayOverTick != 0) && (delayOverTick <= realTicks))){ // 延时时间到
                switch(*flag){
                    case KORO_A_BLINK + KORO_A_OFFSET:
                        delayOverTick = koro_anime_blink(&myWs, koroAnime.ForT, &koroAnime.rgb888);
                        break;
                        
                    case KORO_A_BREATHE + KORO_A_OFFSET:
                        delayOverTick = koro_anime_breathe(&myWs, koroAnime.ForT, &koroAnime.rgb888);
                        break;

                    default:
                        delayOverTick = 0;
                        break;
                }
                if(delayOverTick != 0){
                    delayOverTick += realTicks;
                }else {
                    *flag = 0;
                }
            }
            break;
    }

}

// ws2812 守护进程，控制动画播放总时长
void task_ws2812d_func(void *param){
    static uint32_t delayOverTick = 0;
    uint8_t *flag = ((taskCtrl *)param)->flag;

    switch(*flag){
        case 0: // 挂起
            ((taskCtrl *)param)->tickCounts = 0;
            break;

        default:
            if(delayOverTick == 0){
                delayOverTick = wsAnimeTime * 1000 + realTicks;
                ((taskCtrl *)param)->tickCounts = 1;
            }
            if(delayOverTick != 0 && delayOverTick <= realTicks){
                delayOverTick = 0;
                *flag = 0;
                wsAnimeFlag = 2;
            }

            break;
    }
}

// rc522 读卡任务
void task_rc522_func(void *param){
    int status;
    struct koroCardDataStu cardData;
    status = koro_read_card(&myKoro, &cardData);
    static uint8_t lastCardID = 0;
    static uint8_t noCardCount = 0;

    switch(status){
        case KORO_OK:
            if(cardData.id != lastCardID){
                noCardCount = 0;
                koro_analyze_data(&myKoro, &cardData);
                printf_DMA(PRINT_LOG"Read koro card data: id: %d, maddr: 0x%04x, meshData: 0x%02x\n", cardData.id, cardData.meshAddrU.meshADDR_16, cardData.meshData);
                printf_DMA(PRINT_LOG"\taudioFolder: %d, audioIndex: %d\n", cardData.audioFolder, cardData.audioIndex);
                lastCardID = cardData.id;
            }
            break;
            
        case KORO_ERR:
            lastCardID = 0;
            printf_DMA(PRINT_WARNNING"Read card ERROR!\n");

            break;
        
        case KORO_NOCARD:
            noCardCount ++;
            if(noCardCount > 3){
                noCardCount = 0;
                lastCardID = 0;
            }

            break;
            
        case KORO_NOTKORO:
            lastCardID = 0;
            printf_DMA(PRINT_WARNNING"This is not koro card!\n");

            break;

        default:
            break;

    }

}

/*
// 检测电池状态
void task_battery_func(void *param){
    static uint8_t batRemindCounts = 0;
    uint8_t batPct = get_battery_percent();

    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12)){ // 未插入充电线
        if(batPct < 20){
            if(batRemindCounts == 0){
                printf_DMA(PRINT_LOG"Low battery...\n");
                batRemindCounts = 10; // 每隔 10s 提醒一次
                // 播放音频
                ch_play_folder(&myCh, AUDIO_FOLDER_SYSTEM, AUDIO_SYSTEM_BATTERY_LOW);

                // 播放灯效
                koroAnime.anime = KORO_A_BLINK;
                koroAnime.ForT = 4;
                koroAnime.seconds = 1;
                koroAnime.rgb888.red = 50;
                koroAnime.rgb888.green = 0;
                koroAnime.rgb888.blue = 50;

                koro_anime_play(&koroAnime);
            }else {
                batRemindCounts --;
            }
        }

    }else { // 已插入充电线
        if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)){ // 已充满
            if(batRemindCounts == 0){
                printf_DMA(PRINT_LOG"Battery full.\n");
                batRemindCounts = 30; // 每隔 30s 提醒一次
                // 播放音频
                ch_play_folder(&myCh, AUDIO_FOLDER_SYSTEM, AUDIO_SYSTEM_BATTERY_FULL);

                // 播放灯效
                koroAnime.anime = KORO_A_BLINK;
                koroAnime.ForT = 4;
                koroAnime.seconds = 1;
                koroAnime.rgb888.red = 0;
                koroAnime.rgb888.green = 50;
                koroAnime.rgb888.blue = 0;

                koro_anime_play(&koroAnime);
            }else {
                batRemindCounts --;
            }

        }else { // 未充满
            
        }
    }
}
*/

// 检测电池状态
void task_battery_func(void *param){
    static uint8_t batRemindCounts = 0;
    uint8_t batPct = get_battery_percent();

    if(batPct < 20){ // 电量不足
        if(batRemindCounts == 0){
            printf_DMA(PRINT_LOG"Low battery...\n");
            batRemindCounts = 15; // 每隔 15s 提醒一次
            // 播放音频
            ch_play_folder(&myCh, AUDIO_FOLDER_SYSTEM, AUDIO_SYSTEM_BATTERY_LOW);

            // 播放灯效
            koroAnime.anime = KORO_A_BLINK;
            koroAnime.ForT = 4; // 频率 4 Hz
            koroAnime.seconds = 1; // 播放 1s
            // 颜色
            koroAnime.rgb888.red = 50;
            koroAnime.rgb888.green = 0;
            koroAnime.rgb888.blue = 50;

            // 设置灯效播放任务
            koro_anime_play(&koroAnime);
        }else {
            batRemindCounts --;
        }
    }
}


void task_schedule(void){
    uint8_t i;
    if(u1RecFlag){ // 处理接收到的命令
        u1RecFlag = 0;
        process_command(u1RecBuf);
    }
    // 当倒计时结束或设定的任务标志位非 0，运行该任务
    for(i = 0; taskList[i].tickReload != 0; i++){
        if(taskList[i].flag != NULL && *(taskList[i].flag) != 0){
            taskList[i].run ++;
        }
        if(taskList[i].run != 0){
            taskList[i].run --;
            taskList[i].pTaskFunc(&taskList[i]);
        }
    }
}

void tick_tack(void){
    uint8_t i;
    realTicks ++;
    for(i = 0; taskList[i].tickReload != 0; i++){
        if(--taskList[i].tickCounts == 0){
            taskList[i].tickCounts = taskList[i].tickReload;
            taskList[i].run ++;
        }
    }
}

extern TIM_HandleTypeDef htim2;
void start_schedule(void){
    HAL_TIM_Base_Start_IT(&htim2);
}

void stop_schedule(void){
    HAL_TIM_Base_Stop_IT(&htim2);
}


void get_battery_voltage(float *vol){
    uint32_t valBatADC = HAL_ADC_GetValue(&hadc1); // v*68/101/3.3(vref?)*4096=adc
    *vol = valBatADC / 835.66756f;
    // printf_DMA(PRINT_DEBUG"Read adc: %d\n", valBatADC);
    // printf_DMA(PRINT_DEBUG"Read bat vol: %.02f\n", *vol);
    // HAL_ADC_Start(&hadc1);
}

uint8_t get_battery_percent(void){
    uint8_t i;
    float voltage;

    get_battery_voltage(&voltage);

    voltage *= 100;
    for(i = 0; i < 10; i++){
        if(voltage > volTable[i+1]){
            continue;
        }
        if(i == 0){
            if(voltage > volTable[0]){
                voltage = i * 10 + (voltage - volTable[i])*10/(volTable[i+1] - volTable[i]);
            }else {
                voltage = 0;
            }
        }else {
            voltage = i * 10 + (voltage - volTable[i])*10/(volTable[i+1] - volTable[i]);
        }
        break;
    }
    if(i == 10){
        // printf_DMA(PRINT_DEBUG"Read bat percent: 100%%\n");
        return 99;
    }

    // printf_DMA(PRINT_DEBUG"Read bat percent: %d%%\n", (uint8_t)voltage);
    return (uint8_t)voltage;
}
